/**
 * Copyright 2008 by Robert Konigsberg
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the same terms as Perl.
 *
 * @see http://www.perl.com/perl/misc/Artistic.html
 */
package visitor.maze;

import java.util.Collections;
import java.util.EnumMap;
import java.util.Map;
import java.util.Set;

/**
 * A room in the maze.
 *
 * A room has an identifier, and can have up to four exits (one exit per
 * direction).
 *
 * Implementations should not create Room objects on their own. Instead, they
 * should use the {@link MazeBuilder}.
 *
 * Room objects have reliable {@code equals} and {@code hashCode} methods, and
 * as such can reliably be used in sets or as map keys.
 *
 * @author kberg
 */
public class Room {
  private final int id;
  private final Map<Direction, Room> exits;

  Room(int id) {
    this.id = id;
    this.exits = new EnumMap<Direction, Room>(Direction.class);
  }

  void setExit(Direction direction, Room room) {
    if (exits.containsKey(direction)) {
      throw new IllegalArgumentException(this.toString() +
          " already has an exit facing " + direction);
    }
    exits.put(direction, room);
  }

  public Room getExit(Direction direction) {
    return exits.get(direction);
  }

  public int getId() {
    return id;
  }

  public Set<Direction> getExits() {
    return Collections.unmodifiableSet(exits.keySet());
  }

  public void accept(Visitor visitor) {
    if (visitor.shouldVisit(this)) {
      visitor.visit(this);
      for (Direction direction : exits.keySet()) {
        exits.get(direction).accept(visitor);
      }
    }
  }

  void destroy() {
    exits.clear();
  }

  @Override
  public String toString() {
    return "Room " + getId();
  }

  @Override
  public int hashCode() {
    return getId();
  }

  /**
   * Returns {@code true} if this is equivalent to {@code obj}.
   *
   * Room objects currently use their id for equality, rather than the
   * equivalence. This means it's possible to create two Room objects with the
   * same id, connect them to different parts of a maze, and still be
   * equivalent to each other. It's expected that whatever is responsible
   * for constructing the Room objects prevents multiple instances from having
   * the same id.
   */
  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (!(obj instanceof Room)) {
      return false;
    }
    Room other = (Room) obj;
    return id == other.id;
  }
}
